use std::fs::File;
use std::io::{BufRead, BufReader};
use std::io;

enum Instruction {
    Forward(i32),
    Down(i32),
    Up(i32),
}

impl From<String> for Instruction {
    fn from(value: String) -> Self {
        if value.starts_with("forward") {
            return Instruction::Forward( (&value[8..]).parse().unwrap() )
        } else if value.starts_with("down") {
            return Instruction::Down( (&value[5..]).parse().unwrap() )
        } else if value.starts_with("up") {
            return Instruction::Up( (&value[3..]).parse().unwrap() )
        } 
        panic!("");
    }
}

#[allow(unused)]
fn part1(instructions: &Vec<Instruction>) {
    type Position = (i32, i32);

    fn execute(position: Position, instruction: &Instruction) -> Position {
        let (horizontal, depth) = position;
        match instruction {
            Instruction::Forward(dis) => (horizontal + dis, depth),
            Instruction::Down(dis) => (horizontal, depth + dis),
            Instruction::Up(dis) => (horizontal, depth - dis),
        }
    }

    let (horizontal, depth) = instructions.iter().fold((0, 0), execute);

    println!("{}", horizontal * depth);
}

#[allow(unused)]
fn part2(instructions: &Vec<Instruction>) {
    type Position = (i32, i32, i32);

    fn execute(position: Position, instruction: &Instruction) -> Position {
        let (horizontal, depth, aim) = position;
        match instruction {
            Instruction::Forward(dis) => (horizontal + dis, depth + aim * dis, aim),
            Instruction::Down(dis) => (horizontal, depth, aim + dis),
            Instruction::Up(dis) => (horizontal, depth, aim - dis),
        }
    }

    let (horizontal, depth, _) = instructions.iter().fold((0, 0, 0), execute);

    println!("{}", horizontal * depth);
}

fn main() -> io::Result<()>  {
    let file = File::open("./day02/input.txt")?;
    let reader = BufReader::new(file);

    let instructions: Vec<Instruction> = 
        reader.lines().map(|line| line.unwrap().into()).collect();

    part1(&instructions);
    part2(&instructions);

    Ok(())
}
